package com.apes.framework.plugin.esb.processor;

import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.ApesBean;
import com.apes.framework.plugin.esb.api.Request;
import com.apes.framework.util.CacheUtil;
import com.apes.framework.util.DistributedLock;
import com.apes.framework.util.ReflectUtil;
import lombok.Data;
import lombok.SneakyThrows;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 功能：Lock处理器类
 *
 * @author xul
 * @create 2020-07-17 9:16
 */
@Data
public class LockProcessor<T extends Request, R> extends AbstractChainProcessor<T, R> {
    private String key = "default";
    /**
     * 最长加锁时间：5分钟
     **/
    private static final long millisecond = 5 * 60 * 1000;

    @Override
    public R process(T data) {
        DistributedLock distributedLock = SpringManager.getBean(DistributedLock.class);
        String lockId = LockProcessor.class.getSimpleName() + "_" + getLockId(data);
        lock(distributedLock, lockId);
        return super.process(data);
    }

    @SneakyThrows
    private void lock(DistributedLock distributedLock, String lockId) {
        int retries = 1;
        do {
            if (distributedLock.lock(lockId, millisecond)) {
                DistributedLock.add(lockId);
                return;
            }
            TimeUnit.MILLISECONDS.sleep(100);
        } while (retries++ < 100); /**最长等待时间：10秒**/
        throw new RuntimeException("资源：" + lockId + "使用中，请稍后重试！");
    }

    private String getLockId(T data) {
        Object record = data.getData();
        if (record instanceof ApesBean) {
            record = ReflectUtil.getMerge(record);
        } else if (record instanceof String) {
            record = data.getMap();
        }
        if (!(record instanceof Map)) {
            throw new RuntimeException("record element Expected. Got - " + record.getClass());
        }
        String result = key;
        try {
            Object value = CacheUtil.getEngine().execute(key, record);
            if (!StringUtils.isEmpty(value)) {
                result = (String) value;
            }
        } catch (Exception e) {
        }
        return result;
    }


    @Override
    protected R doProcess(T data) {
        return null;
    }
}
